package com.gitee.apanlh.util.io;

import com.gitee.apanlh.exp.NotFoundException;
import com.gitee.apanlh.exp.StreamCopyException;
import com.gitee.apanlh.exp.StreamReadException;
import com.gitee.apanlh.exp.StreamWriteException;
import com.gitee.apanlh.util.base.Empty;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.encode.CharsetCode;
import com.gitee.apanlh.util.encode.StrEncodeUtils;
import com.gitee.apanlh.util.file.FileUtils;
import com.gitee.apanlh.util.unit.BuffSize;
import com.gitee.apanlh.util.valid.ValidParam;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Reader;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.List;

/**
 * 	文件流操作相关工具类
 * 
 * 	@author Pan 
 */
public class FileIOUtils {
		
	/**
	 * 	构造函数
	 * 
	 * 	@author Pan
	 */
	private FileIOUtils() {
		//	不允许外部实例
		super();
	}

	/**	
	 * 	获取文件输入流
	 * 	<br>将保持输入流开放
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath			文件路径
	 * 	@return	FileInputStream
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static FileInputStream getInput(String filePath) {
		return getInput(new File(filePath));
	}
	
	/**	
	 * 	获取文件输入流
	 * 	<br>将保持输入流开放
	 * 	
	 * 	@author Pan
	 * 	@param 	file				文件
	 * 	@return	FileInputStream
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static FileInputStream getInput(File file) {
		try {
			return new FileInputStream(file);
		} catch (Exception e) {
			throw new NotFoundException(e.getMessage(), e);
		}
	}
	
	/**	
	 * 	获取文件输出流
	 * 	<br>将保持输出流开放
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath			文件路径
	 * 	@return	FileOutputStream
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static FileOutputStream getOutput(String filePath) {
		return getOutput(new File(filePath), false);
	}
	
	/**	
	 * 	获取文件输出流
	 * 	<br>将保持输出流开放
	 * 	<br>自定义追加标识
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath			文件路径
	 * 	@param 	append				追加写入(true时将写入到文件的末尾，false为直接覆盖)
	 * 	@return	FileOutputStream
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static FileOutputStream getOutput(String filePath, boolean append) {
		return getOutput(new File(filePath), append);
	}
	
	/**	
	 * 	获取文件输出流
	 * 	<br>将保持输出流开放
	 * 	
	 * 	@author Pan
	 * 	@param 	file				文件
	 * 	@return	FileOutputStream
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static FileOutputStream getOutput(File file) {
		return getOutput(file, false);
	}
	
	/**	
	 * 	获取文件输出流
	 * 	<br>将保持输出流开放
	 * 	<br>自定义追加标识
	 * 	
	 * 	@author Pan
	 * 	@param 	file				文件
	 * 	@param 	append				追加写入(true时将写入到文件的末尾，false为直接覆盖)
	 * 	@return	FileOutputStream
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static FileOutputStream getOutput(File file, boolean append) {
		try {
			return new FileOutputStream(file, append);
		} catch (Exception e) {
			throw new NotFoundException(e.getMessage(), e);
		}
	}
	
	/**
	 * 	获取缓冲写入器
	 * 	<br>默认系统字符编码
	 * 	<br>默认8K缓冲区
	 * 	<br>将保持流开放
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath	 		文件路径
	 * 	@return	FileWriter
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static BufferedWriter getWriter(String filePath) {
		return getWriter(new File(filePath), false);
	}
	
	/**	
	 * 	获取缓冲写入器
	 * 	<br>将保持流开放
	 * 	<br>自定义追加标识
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath			文件路径
	 * 	@param 	append				追加写入(true时将写入到文件的末尾)
	 * 	@return	FileWriter
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static BufferedWriter getWriter(String filePath, boolean append) {
		return getWriter(new File(filePath), append);
	}
	
	/**
	 * 	获取缓冲写入器
	 * 	<br>将保持流开放
	 * 	<br>文件覆盖式
	 * 	
	 * 	@author Pan
	 * 	@param 	file				文件对象
	 * 	@return	FileWriter
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static BufferedWriter getWriter(File file) {
		return getWriter(file, false);
	}
	
	/**	
	 * 	获取缓冲写入器
	 * 	<br>将保持流开放
	 * 	<br>自定义追加标识
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	file				文件
	 * 	@param 	append				追加写入(true时将写入到文件的末尾) false为覆盖式
	 * 	@return	FileWriter
	 * 	@throws NotFoundException	当系统不存在路径或不存在文件时抛出异常
	 */
	public static BufferedWriter getWriter(File file, boolean append) {
		try {
			return new BufferedWriter(new FileWriter(file, append));
		} catch (Exception e) {
			throw new NotFoundException(e.getMessage(), e);
		}
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出流中
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认自动关闭输入流
	 * 	<br>默认自动关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is	 				输入流
	 * 	@param 	fos	 				文件输出流
	 * 	@return long 				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileOutputStream fos) {
		return copy(is, fos, BuffSize.SIZE_8K);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出流中
	 * 	<br>默认8K缓冲区长度
	 * 	<br>自定义关闭输入流
	 * 	<br>自定义关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	is	 				输入流
	 * 	@param 	fos					文件输出流
	 * 	@param 	isCloseOutputStream	true关闭输出流
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileOutputStream fos,  boolean isCloseOutputStream) {
		return copy(is, fos, BuffSize.SIZE_8K, true, isCloseOutputStream);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出流中
	 * 	<br>自定义缓冲区长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>默认自动关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	is	 				输入流
	 * 	@param 	fos					文件输出流
	 * 	@param 	buffSize			缓冲区长度
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileOutputStream fos, int buffSize) {
		return copy(is, fos, buffSize, true, true);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出流中
	 * 	<br>自定义缓冲区长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>自定义关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	is	 				输入流
	 * 	@param 	fos					文件输出流
	 * 	@param 	buffSize			缓冲区长度
	 * 	@param 	isCloseOutputStream	true关闭输出流
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileOutputStream fos, int buffSize, boolean isCloseOutputStream) {
		return copy(is, fos, buffSize, true, isCloseOutputStream);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出流中
	 * 	<br>自定义缓冲区长度
	 * 	<br>自定义关闭输入流
	 * 	<br>自定义关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is	 				输入流
	 * 	@param 	fos	 				文件输出流
	 * 	@param 	buffSize			缓冲区长度
	 * 	@param 	isCloseInputStream	true关闭输入流
	 * 	@param 	isCloseOutputStream	true关闭输出流
	 * 	@return long 				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileOutputStream fos, int buffSize, boolean isCloseInputStream, boolean isCloseOutputStream) {
		if (fos == null) {
			if (isCloseInputStream) {
				IOUtils.close(is);
			}
			return -1L;
		}
		return copy(is, fos.getChannel(), buffSize, isCloseInputStream, isCloseOutputStream);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出管道中
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认自动关闭输入流
	 * 	<br>默认自动关闭输出管道
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is	 				输入流
	 * 	@param 	outChannel	 		文件输出管道
	 * 	@return long 				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileChannel outChannel) {
		return copy(is, outChannel, BuffSize.SIZE_8K);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出管道中
	 * 	<br>默认8K缓冲区长度
	 * 	<br>自定义关闭输入流
	 * 	<br>自定义关闭输出管道
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	is	 					输入流
	 * 	@param 	outChannel	 			文件输出管道
	 * 	@param 	isCloseOutputStream		是否关闭输出流 true关闭
	 * 	@return long					拷贝字节
	 * 	@throws	StreamCopyException		拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileChannel outChannel, boolean isCloseOutputStream) {
		return copy(is, outChannel, BuffSize.SIZE_8K, true, isCloseOutputStream);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出管道中
	 * 	<br>自定义缓冲区长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>默认自动关闭输出管道
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	is	 				输入流
	 * 	@param 	outChannel	 		文件输出管道
	 * 	@param 	buffSize			缓冲区长度
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileChannel outChannel, int buffSize) {
		return copy(is, outChannel, buffSize, true, true);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出管道中
	 * 	<br>自定义缓冲区长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>自定义关闭输出管道
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	is	 					输入流
	 * 	@param 	outChannel	 			文件输出管道
	 * 	@param 	buffSize				缓冲区长度
	 * 	@param 	isCloseOutputStream		是否关闭输出流 true关闭
	 * 	@return long					拷贝的字节数
	 * 	@throws	StreamCopyException		拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileChannel outChannel, int buffSize, boolean isCloseOutputStream) {
		return copy(is, outChannel, buffSize, true, isCloseOutputStream);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出管道中
	 * 	<br>自定义缓冲区长度
	 * 	<br>自定义关闭输入流
	 * 	<br>自定义关闭输出管道
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is	 					输入流
	 * 	@param 	outChannel	 			文件输出管道
	 * 	@param 	buffSize				缓冲区长度
	 * 	@param 	isCloseInputStream		true关闭输入流
	 * 	@param 	isCloseOutputChannel	true关闭输出管道
	 * 	@return long 					拷贝的字节数
	 * 	@throws	StreamCopyException		拷贝异常时抛出
	 */
	public static long copy(InputStream is, FileChannel outChannel, int buffSize, boolean isCloseInputStream, boolean isCloseOutputChannel) {
		boolean isEx = false;
		try {
			if (buffSize <= 0) {
				buffSize = BuffSize.SIZE_8K;
			}
			
			byte[] bufferByte = BuffSize.newBufferByte(buffSize);
			int len;
			long writeTotal = 0L;
			
			while ((len = is.read(bufferByte)) != -1) {
				writeTotal += outChannel.write(ByteBuffer.wrap(bufferByte, 0, len));
			}
			return writeTotal;
		} catch (Exception e) {
			isEx = true;
			IOUtils.close(outChannel, is);
			throw new StreamCopyException(e.getMessage(), e);
		} finally {
			if (!isEx) {
				if (isCloseOutputChannel) {
					IOUtils.close(outChannel);
				}
				if (isCloseInputStream) {
					IOUtils.close(is);
				}
			}
		}
	}
	
	/**	
	 * 	将文件输入流内容拷贝至文件输出流中
	 * 	<br>默认使用自动优化块长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>默认自动关闭输出流
	 * 
	 * 	@author Pan
	 * 	@param 	fis	 				文件输入流
	 * 	@param 	fos	 				文件输出流
	 * 	@return long 				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(FileInputStream fis, FileOutputStream fos) {
		return copy(fis, fos, -1);
	}
	
	/**	
	 * 	将文件输入流内容拷贝至文件输出流中
	 * 	<br>自定义读取/写入块长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>默认自动关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	fis					文件输入流
	 * 	@param 	fos					文件输出流
	 * 	@param 	blockSize			拷贝块长度
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(FileInputStream fis, FileOutputStream fos, int blockSize) {
		return copy(fis, fos, blockSize, true, true);
	}
	
	/**	
	 * 	将文件输入流内容拷贝至文件输出流中
	 * 	<br>自定义读取/写入块长度
	 * 	<br>默认自动关闭输入流
	 * 	<br>自定义关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan	
	 * 	@param 	fis					文件输入流
	 * 	@param 	fos					文件输出流
	 * 	@param 	blockSize			拷贝块长度
	 * 	@param 	isCloseOutputStream	true关闭输出流
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(FileInputStream fis, FileOutputStream fos, int blockSize, boolean isCloseOutputStream) {
		return copy(fis, fos, blockSize, true, isCloseOutputStream);
	}
	
	/**	
	 * 	将输入流内容拷贝至文件输出流中
	 * 	<br>自定义读取/写入块长度
	 * 	<br>自定义关闭输入流
	 * 	<br>自定义关闭输出流
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	fis					文件输入流
	 * 	@param 	fos					文件输出流
	 * 	@param 	blockSize			拷贝块长度
	 * 	@param 	isCloseInputStream	true关闭输入流
	 * 	@param 	isCloseOutputStream	true关闭输出流
	 * 	@return long				拷贝的字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long copy(FileInputStream fis, FileOutputStream fos, int blockSize, boolean isCloseInputStream, boolean isCloseOutputStream) {
		boolean isEx = false;
		try {
			FileChannel fisChannel = fis.getChannel();
			FileChannel fosChannel = fos.getChannel();
			long size = fisChannel.size();
			long position = 0L;
			
			//	使用FileChannel优化读取块
			if (blockSize < 1) {
				return fisChannel.transferTo(0, size, fosChannel);
			}
			
			ByteBuffer buffer = ByteBuffer.allocate((int) Math.min(blockSize, size));
			
			while (position < size) {
				if (fisChannel.read(buffer) < 0) {
					break;
				}
				buffer.flip();
				int remaining = buffer.remaining();
				fosChannel.write(buffer, remaining);
				buffer.clear();
				position += remaining;
			}
			return position;
		} catch (Exception e) {
			isEx = true;
			IOUtils.close(fos, fis);
			throw new StreamCopyException(e.getMessage(), e);
		} finally {
			if (!isEx) {
				if (isCloseOutputStream) {
					IOUtils.close(fos);
				}
				if (isCloseInputStream) {
					IOUtils.close(fis);
				}
			}
		}
	}

	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认UTF-8字符集编码
	 * 	<br>默认将关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	fos					文件输出流
	 * 	@return	int					返回写入字节数
	 */
	public static int write(String str, FileOutputStream fos) {
		return write(str, fos, CharsetCode.UTF_8, BuffSize.SIZE_8K, true, FileWriteMode.ZERO_COPY);
	}

	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认UTF-8字符集编码
	 * 	<br>自定义关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, boolean isCloseOutputStream) {
		return write(str, fos, CharsetCode.UTF_8, BuffSize.SIZE_8K, isCloseOutputStream, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认UTF-8字符集编码
	 * 	<br>自定义关闭文件输出流
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, boolean isCloseOutputStream, FileWriteMode mode) {
		return write(str, fos, BuffSize.SIZE_8K, isCloseOutputStream, mode);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>默认UTF-8字符集编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认将关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos					文件输出流
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return	int					返回写入字节数
	 */
	public static int write(String str, FileOutputStream fos, int bufferSize) {
		return write(str, fos, CharsetCode.UTF_8, bufferSize, true, FileWriteMode.ZERO_COPY);
	}

	/**
	 * 	文件输出流写入
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>默认UTF-8字符集编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, int bufferSize, boolean isCloseOutputStream) {
		return write(str, fos, CharsetCode.UTF_8, bufferSize, isCloseOutputStream, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	 文件输出流写入
	 * 	<br>默认UTF-8字符编码集
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭文件输出流
	 * 
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, int bufferSize, boolean isCloseOutputStream, FileWriteMode mode) {
		return write(str, fos, CharsetCode.UTF_8, bufferSize, isCloseOutputStream, mode);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认将关闭文件输出流
	 * 	<br>自定义集编码
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos					文件输出流
	 * 	@param 	charset				字符集编码
	 * 	@return	int					返回写入字节数
	 */
	public static int write(String str, FileOutputStream fos, String charset) {
		return write(str, fos, charset, BuffSize.SIZE_8K, true, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义字符集编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认将关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos					文件输出流
	 * 	@param 	charset				字符集编码
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return	int					返回写入字节数
	 */
	public static int write(String str, FileOutputStream fos, String charset, int bufferSize) {
		return write(str, fos, charset, bufferSize, true, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符集编码
	 * 	<br>自定义关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	charset					字符集编码
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, String charset, boolean isCloseOutputStream) {
		return write(str, fos, charset, BuffSize.SIZE_8K, isCloseOutputStream, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符集编码
	 * 	<br>自定义关闭文件输出流
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	charset					字符集编码
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, String charset, boolean isCloseOutputStream, FileWriteMode mode) {
		return write(str, fos, charset, BuffSize.SIZE_8K, isCloseOutputStream, mode);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义字符集编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	charset					字符集编码
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, String charset, int bufferSize, boolean isCloseOutputStream) {
		return write(str, fos, charset, bufferSize, isCloseOutputStream, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	 文件输出流写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义字符集编码
	 * 	<br>自定义关闭文件输出流
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭文件输出流
	 * 
	 * 	@author Pan
	 * 	@param 	str						字符串
	 * 	@param 	fos						文件输出流
	 * 	@param 	charset					字符集编码
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(String str, FileOutputStream fos, String charset, int bufferSize, boolean isCloseOutputStream, FileWriteMode mode) {
		if (fos == null) {
			return -1;
		}
		return write(StrEncodeUtils.utf8EncodeToBytes(str, charset), fos.getChannel(), bufferSize, isCloseOutputStream, mode);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认将关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	fos						文件输出流
	 * 	@return	int					返回写入字节数
	 */
	public static int write(byte[] bytes, FileOutputStream fos) {
		return write(bytes, fos, BuffSize.SIZE_8K, true, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fos						文件输出流
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileOutputStream fos, boolean isCloseOutputStream) {
		return write(bytes, fos, BuffSize.SIZE_8K, isCloseOutputStream, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fos						文件输出流
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileOutputStream fos, boolean isCloseOutputStream, FileWriteMode mode) {
		return write(bytes, fos, BuffSize.SIZE_8K, isCloseOutputStream, mode);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认将关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	fos					文件输出流
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return	int					返回写入字节数
	 */
	public static int write(byte[] bytes, FileOutputStream fos, int bufferSize) {
		return write(bytes, fos, bufferSize, true, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件输出流写入
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭文件输出流
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fos						文件输出流
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileOutputStream fos, int bufferSize, boolean isCloseOutputStream) {
		return write(bytes, fos, bufferSize, isCloseOutputStream, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	 文件输出流写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭文件输出流
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭文件输出流
	 * 
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fos						文件输出流
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseOutputStream		是否关闭文件输出流
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileOutputStream fos, int bufferSize, boolean isCloseOutputStream, FileWriteMode mode) {
		if (fos == null) {
			return -1;
		}
		return write(bytes, fos.getChannel(), bufferSize, isCloseOutputStream, mode);
	}
	
	/**
	 * 	文件写入(管道方式写入)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认将关闭管道
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭管道
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	fc					file管道
	 * 	@return	int					返回写入字节数
	 */
	public static int write(byte[] bytes, FileChannel fc) {
		return write(bytes, fc, BuffSize.SIZE_8K, true, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件写入(管道方式写入)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义关闭管道
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭管道
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fc						file管道
	 * 	@param 	isCloseChannel			是否关闭文件管道
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileChannel fc, boolean isCloseChannel) {
		return write(bytes, fc, BuffSize.SIZE_8K, isCloseChannel, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件写入(管道方式写入)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义关闭管道
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭管道
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fc						file管道
	 * 	@param 	isCloseChannel			是否关闭文件管道
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileChannel fc, boolean isCloseChannel, FileWriteMode mode) {
		return write(bytes, fc, BuffSize.SIZE_8K, isCloseChannel, mode);
	}
	
	/**
	 * 	文件写入(管道方式写入)
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认将关闭管道
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭管道
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	fc					file管道
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return	int					返回写入字节数
	 */
	public static int write(byte[] bytes, FileChannel fc, int bufferSize) {
		return write(bytes, fc, bufferSize, true, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件写入(管道方式写入)
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭管道
	 * 	<br>零拷贝写入模式
	 * 	<br>异常时关闭管道
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fc						file管道
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseChannel			是否关闭文件管道
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileChannel fc, int bufferSize, boolean isCloseChannel) {
		return write(bytes, fc, bufferSize, isCloseChannel, FileWriteMode.ZERO_COPY);
	}
	
	/**
	 * 	文件写入(管道方式写入)
	 * 	<br>如果bufferSize传递-1将忽略缓冲区，直接写入
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义关闭管道
	 * 	<br>自定义写入模式
	 * 	<br>异常时关闭管道
	 * 	
	 * 	@author Pan
	 * 	@param 	bytes					字节数组
	 * 	@param 	fc						file管道
	 * 	@param 	bufferSize				缓冲区大小
	 * 	@param 	isCloseChannel			是否关闭文件管道
	 * 	@param 	mode					写入模式
	 * 	@return	int						返回写入字节数
	 * 	@throws StreamWriteException	写入异常时抛出
	 */
	public static int write(byte[] bytes, FileChannel fc, int bufferSize, boolean isCloseChannel, FileWriteMode mode) {
		if (fc == null) {
			return -1;
		}
		
		boolean isEx = false;
		ByteBuffer buffer;
		//	数据总数
		int dataTotal = bytes.length;
		//	待写入
		int remaining = dataTotal;
		//	偏移量
		int position = 0;
		//	已写入
		int writeTotal = 0;
		
		try {
			if (FileWriteMode.ZERO_COPY.equals(mode)) {
				if (bufferSize == -1 || dataTotal <= bufferSize) {
					return fc.write(ByteBuffer.wrap(bytes, 0, dataTotal));
				}
				buffer = ByteBuffer.allocate(bufferSize);
			} else {
				buffer = fc.map(MapMode.READ_WRITE, 0, dataTotal);
			}
			
			while (remaining > 0) {
				buffer.put(bytes, position, Math.min(remaining, bufferSize));
				buffer.flip();
				int writeLen = fc.write(buffer);
				buffer.clear();
				
				writeTotal+= writeLen;
				position += writeLen;
				remaining -= writeLen;
			}
		} catch (Exception e) {
			isEx = true;
			IOUtils.close(fc);
			throw new StreamWriteException(e.getMessage(), e);
		} finally {
			if (!isEx && isCloseChannel) {
				IOUtils.close(fc);
			}
		}
		return writeTotal;
	}
	
	/**
	 * 	将字节内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认UTF-8字符编码集
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file) {
		return writeToFile(str, file, CharsetCode.UTF_8);
	}

	/**
	 * 	将字节内容容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认UTF-8字符集编码
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file, int bufferSize) {
		return writeToFile(str, file, CharsetCode.UTF_8, bufferSize);
	}
	
	/**
	 * 	将字节内容内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认UTF-8字符编码集
	 * 	<br>自定义写入方式
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file, boolean appendMode) {
		return writeToFile(str, file, CharsetCode.UTF_8, appendMode);
	}
	
	/**
	 * 	将字节内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符编码集
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@param 	charset				字符编码集
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file, String charset) {
		return writeToFile(str, file, charset, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	将字节内容内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符编码集
	 * 	<br>自定义写入方式
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@param 	charset				字符编码集
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file, String charset, boolean appendMode) {
		return writeToFile(str, file, charset, BuffSize.SIZE_8K, appendMode);
	}
	
	/**
	 * 	将字节内容容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义字符集编码
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@param 	charset				字符编码集
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file, String charset, int bufferSize) {
		return writeToFile(str, file, charset, bufferSize, false);
	}
	
	/**
	 * 	将字节内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>自定义字符集编码
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 	
	 * 	@author Pan
	 * 	@param 	str					字符串
	 * 	@param 	file				文件对象
	 * 	@param 	charset				字符集编码
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(String str, File file, String charset, int bufferSize, boolean appendMode) {
		if (ValidParam.isEmpty(str) || file == null) {
			return -1L;
		}
		if (ValidParam.isEmpty(charset)) {
			charset = CharsetCode.UTF_8;
		}
		
		String path = file.getPath();
		String name = file.getName();
		String directory = StringUtils.subStr(path, 0, path.length() - name.length());
		FileUtils.create(directory, name, false, true);
		
		return writeToFile(IOUtils.toByteInput(StrEncodeUtils.utf8EncodeToBytes(str, charset)), file, bufferSize, appendMode, true);
	}
	
	/**
	 * 	将字节内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	file				文件对象
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(byte[] bytes, File file) {
		return writeToFile(bytes, file, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	将字节内容内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	file				文件对象
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(byte[] bytes, File file, boolean appendMode) {
		return writeToFile(bytes, file, BuffSize.SIZE_8K, appendMode);
	}
	
	/**
	 * 	将字节内容容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	file				文件对象
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(byte[] bytes, File file, int bufferSize) {
		return writeToFile(bytes, file, bufferSize, false);
	}
	
	/**
	 * 	将字节内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	bytes				字节数组
	 * 	@param 	file				文件对象
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(byte[] bytes, File file, int bufferSize, boolean appendMode) {
		if (ValidParam.isEmpty(bytes) || file == null) {
			return -1L;
		}
		return writeToFile(IOUtils.toByteInput(bytes), file, bufferSize, appendMode, true);
	}
	
	/**
	 * 	将输入流内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is					输入流
	 * 	@param 	file				文件对象
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(InputStream is, File file) {
		return writeToFile(is, file, BuffSize.SIZE_8K);
	}
	
	
	/**
	 * 	将输入流内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is					输入流
	 * 	@param 	file				文件对象
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(InputStream is, File file, boolean appendMode) {
		return writeToFile(is, file, appendMode, true);
	}
	
	/**
	 * 	将输入流内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>自定义关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is					输入流
	 * 	@param 	file				文件对象
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@param 	isCloseInputStream	是否关闭输入流
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(InputStream is, File file, boolean appendMode, boolean isCloseInputStream) {
		return writeToFile(is, file, BuffSize.SIZE_8K, appendMode, isCloseInputStream);
	}
	
	/**
	 * 	将输入流内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>默认覆盖写入
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is					输入流
	 * 	@param 	file				文件对象
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(InputStream is, File file, int bufferSize) {
		return writeToFile(is, file, bufferSize, false, true);
	}
	
	/**
	 * 	将输入流内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>默认关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is					输入流
	 * 	@param 	file				文件对象
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(InputStream is, File file, int bufferSize, boolean appendMode) {
		return writeToFile(is, file, bufferSize, appendMode, true);
	}
	
	/**
	 * 	将输入流内容写入文件中(文件不存在则自动创建文件，当目录不存在时也会自动创建)
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义写入方式
	 * 	<br>自定义关闭输入流 
	 * 	<br>异常会将输出流/输入流自动关闭
	 * 
	 * 	@author Pan
	 * 	@param 	is					输入流
	 * 	@param 	file				文件对象
	 * 	@param 	bufferSize			缓冲区大小
	 * 	@param 	appendMode			是否尾部写入	false覆盖文件 true尾部写入
	 * 	@param 	isCloseOutputStream	是否关闭输出流
	 * 	@return long				返回写入字节数
	 * 	@throws	StreamCopyException	拷贝异常时抛出
	 */
	public static long writeToFile(InputStream is, File file, int bufferSize, boolean appendMode, boolean isCloseOutputStream) {
		if (is == null || file == null) {
			return -1L;
		}

		String path = file.getPath();
		String name = file.getName();
		String directory = StringUtils.subStr(path, 0, path.length() - name.length());
		FileUtils.create(directory, name, false, true);
		return copy(is, getOutput(file, appendMode), bufferSize, true, isCloseOutputStream);
	}

	/**	
	 * 	根据文件路径读取
	 * 	<br>将自动关闭流
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath	文件地址
	 * 	@return	byte[]
	 */
	public static byte[] read(String filePath) {
		return read(getInput(filePath));
	}
	
	/**	
	 * 	根据File文件对象进行读取
	 * 	<br>将自动关闭流
	 * 	
	 * 	@author Pan
	 * 	@param 	file	文件对象
	 * 	@return	byte[]
	 */
	public static byte[] read(File file) {
		return read(getInput(file));
	}
	
	/**	
	 * 	将文件输入流转换byte[]
	 * 	<br>将自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	fis		文件输入流
	 * 	@return	byte[]
	 */
	public static byte[] read(FileInputStream fis) {
		if (fis == null) {
			return Empty.arrayByte();
		}
		
		try {
			return IOUtils.read(fis);
		} catch (Exception e) {
			throw new StreamReadException(e.getMessage(), e);
		} finally {
			IOUtils.close(fis);
		}
	}
	
	/**
	 * 	根据文件地址读取返回字符串
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认系统字符编码
	 * 	<br>自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@return String
	 */
	public static String readString(String filePath) {
		return IOUtils.readString(getInput(filePath));
	}
	
	/**
	 * 	根据文件地址读取返回字符串
	 * 	<br>默认系统字符编码
	 * 	<br>自动关闭输入流
	 * 	<br>自定义缓冲区长度
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@param 	bufferSize	缓冲区大小
	 * 	@return	String
	 */
	public static String readString(String filePath, int bufferSize) {
		return IOUtils.readString(getInput(filePath), bufferSize);
	}
	
	/**
	 * 	根据文件地址读取返回字符串
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符编码
	 * 	<br>自动关闭输入流
	 * 	<br>异常时自动关闭输入流
	 * 
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@param 	charset		编码
	 * 	@return	String
	 */
	public static String readString(String filePath, String charset) {
		return IOUtils.readString(getInput(filePath), charset);
	}
	
	/**
	 * 	根据文件地址读取返回字符串
	 * 	<br>自定义字符编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@param 	charset		编码
	 * 	@param 	bufferSize	缓冲区大小
	 * 	@return	String
	 */
	public static String readString(String filePath, String charset, int bufferSize) {
		return IOUtils.readString(getInput(filePath), charset, bufferSize, true);
	}
	
	/**
	 * 	根据文件对象读取返回字符串
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认系统字符编码
	 * 	<br>自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	file	文件对象
	 * 	@return String
	 */
	public static String readString(File file) {
		return IOUtils.readString(getInput(file));
	}
	
	/**
	 * 	根据文件对象读取返回字符串
	 * 	<br>默认系统字符编码
	 * 	<br>自动关闭输入流
	 * 	<br>自定义缓冲区长度
	 * 	
	 * 	@author Pan
	 * 	@param 	file		文件对象
	 * 	@param 	bufferSize	缓冲区大小
	 * 	@return	String
	 */
	public static String readString(File file, int bufferSize) {
		return IOUtils.readString(getInput(file), bufferSize);
	}
	
	/**
	 * 	根据文件对象读取返回字符串
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符编码
	 * 	<br>自动关闭输入流
	 * 	<br>异常时自动关闭输入流
	 * 
	 * 	@author Pan
	 * 	@param 	file	文件对象
	 * 	@param 	charset	编码
	 * 	@return	String
	 */
	public static String readString(File file, String charset) {
		return IOUtils.readString(getInput(file), charset);
	}
	
	/**
	 * 	根据文件对象读取返回字符串
	 * 	<br>自定义字符编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	file		文件对象
	 * 	@param 	charset		编码
	 * 	@param 	bufferSize	缓冲区大小
	 * 	@return	String
	 */
	public static String readString(File file, String charset, int bufferSize) {
		return IOUtils.readString(getInput(file), charset, bufferSize, true);
	}
	
	/**
	 * 	根据文件流读取返回字符串
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认系统字符编码
	 * 	<br>自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	fis 文件输入流
	 * 	@return String
	 */
	public static String readString(FileInputStream fis) {
		return IOUtils.readString(fis);
	}
	
	/**
	 * 	根据文件流读取返回字符串
	 * 	<br>默认系统字符编码
	 * 	<br>自动关闭输入流
	 * 	<br>自定义缓冲区长度
	 * 	
	 * 	@author Pan
	 * 	@param 	fis 		文件输入流
	 * 	@param 	bufferSize	缓冲区大小
	 * 	@return	String
	 */
	public static String readString(FileInputStream fis, int bufferSize) {
		return IOUtils.readString(fis, bufferSize);
	}
	
	/**
	 * 	根据文件流读取返回字符串
	 * 	<br>默认8K缓冲区大小
	 * 	<br>自定义字符编码
	 * 	<br>自动关闭输入流
	 * 	<br>异常时自动关闭输入流
	 * 
	 * 	@author Pan
	 * 	@param 	fis 	文件输入流
	 * 	@param 	charset	编码
	 * 	@return	String
	 */
	public static String readString(FileInputStream fis, String charset) {
		return IOUtils.readString(fis, charset);
	}
	
	/**
	 * 	根据文件流读取返回字符串
	 * 	<br>自定义字符编码
	 * 	<br>自定义缓冲区大小
	 * 	<br>自动关闭输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	fis 		文件输入流
	 * 	@param 	charset		编码
	 * 	@param 	bufferSize	缓冲区大小
	 * 	@return	String
	 */
	public static String readString(FileInputStream fis, String charset, int bufferSize) {
		return IOUtils.readString(fis, charset, bufferSize, true);
	}
	
	/**
	 * 	根据文件地址读取行
	 * 	<br>默认系统字符集编码
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param 	filePath			文件路径
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(String filePath) {
		return readLine(filePath, CharsetCode.getDefaultToString());
	}
	
	/**
	 * 	根据文件地址读取行
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param 	filePath			文件路径
	 * 	@param 	charset				字符集编码
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(String filePath, String charset) {
		return new ReadLineIterator(filePath, charset, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	根据文件对象读取行
	 * 	<br>默认系统字符集编码
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param  file 				文件对象
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(File file) {
		return readLine(file, CharsetCode.getDefaultToString());
	}
	
	/**
	 * 	根据文件对象读取行
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param 	file				文件路径
	 * 	@param 	charset				字符集编码
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(File file, String charset) {
		return new ReadLineIterator(file, charset, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	根据文件输入流读取行
	 * 	<br>默认系统字符集编码
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param  fis 				文件输入流
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(FileInputStream fis) {
		return readLine(fis, CharsetCode.getDefaultToString());
	}
	
	/**
	 * 	根据读取流读取行
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param  fis 				文件输入流
	 * 	@param 	charset				字符集编码
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(FileInputStream fis, String charset) {
		if (fis == null) {
			return null;
		}
		return new ReadLineIterator(fis, charset, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	根据文件输入流读取行
	 * 	<br>默认8K缓冲区大小
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param  reader 				输入流
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(Reader reader) {
		return readLine(reader, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	根据文件输入流读取行
	 * 	<br>自定义缓冲区大小
	 * 	<br>需要自行关闭迭代器流{@link ReadLineIterator#close()}
	 * 	<br>如果迭代器未找到元素时才将会自动关闭流
	 * 
	 * 	@author Pan
	 * 	@param  reader 				输入流
	 * 	@param  bufferSize 			缓冲区大小
	 * 	@return FileLineIterator	文件行迭代器
	 */
	public static ReadLineIterator readLine(Reader reader, int bufferSize) {
		return new ReadLineIterator(reader, bufferSize);
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@return List		行集合
	 */
	public static List<String> readLines(String filePath) {
		return readLines(filePath, CharsetCode.getDefaultToString());
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@param 	charset		字符集编码
	 * 	@return List		行集合
	 */
	public static List<String> readLines(String filePath, String charset) {
		ReadLineIterator readLineIterator = new ReadLineIterator(filePath, charset, BuffSize.SIZE_8K);
		try {
			return readLineIterator.getLines();
		} finally {
			readLineIterator.close();
		}
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 
	 * 	@author Pan
	 * 	@param  file 		文件对象
	 * 	@return List		行集合
	 */
	public static List<String> readLines(File file) {
		return readLines(file, CharsetCode.getDefaultToString());
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 
	 * 	@author Pan
	 * 	@param 	file		文件路径
	 * 	@param 	charset		字符集编码
	 * 	@return List		行集合
	 */
	public static List<String> readLines(File file, String charset) {
		ReadLineIterator readLineIterator = new ReadLineIterator(file, charset, BuffSize.SIZE_8K);

		try {
			return readLineIterator.getLines();
		} finally {
			readLineIterator.close();
		}
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 
	 * 	@author Pan
	 * 	@param  fis 		文件输入流
	 * 	@return List		行集合
	 */
	public static List<String> readLines(FileInputStream fis) {
		return readLines(fis, CharsetCode.getDefaultToString());
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 
	 * 	@author Pan
	 * 	@param  fis 		文件输入流
	 * 	@param 	charset		字符集编码
	 * 	@return List		行集合
	 */
	public static List<String> readLines(FileInputStream fis, String charset) {
		if (fis == null) {
			return Empty.list();
		}
		ReadLineIterator readLineIterator = new ReadLineIterator(fis, charset, BuffSize.SIZE_8K);

		try {
			return readLineIterator.getLines();
		} finally {
			readLineIterator.close();
		}
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 
	 * 	@author Pan
	 * 	@param  reader 		输入流
	 * 	@return List		行集合
	 */
	public static List<String> readLines(Reader reader) {
		return readLines(reader, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	根据文件地址读取所有行
	 * 	<br>默认系统字符集编码
	 * 	<br>自定义字符集编码
	 * 	<br>默认8K缓冲区大小
	 * 
	 * 	@author Pan
	 * 	@param  reader 		输入流
	 * 	@param  bufferSize 	缓冲区大小
	 * 	@return List		行集合
	 */
	public static List<String> readLines(Reader reader, int bufferSize) {
		if (reader == null) {
			return Empty.list();
		}
		ReadLineIterator readLineIterator = new ReadLineIterator(reader, bufferSize);

		try {
			return readLineIterator.getLines();
		} finally {
			readLineIterator.close();
		}
	}
}
